In this article:
- Exporting to Vector Formats (PDF, SVG, XPS)
- Exporting Multiple Charts to a Single Image
- Exporting Multiple Charts to Separate Images
- Exporting an Entire View That Contains a Chart
- Exporting Charts from Multiple Tabs
- Showing or Hiding Cursors on an Exported Chart
- Adding Annotations or Visual Elements to an Exported Chart
- Placing Custom UI Elements on an Exported Chart
- Changing the Theme or Background Color for Export
- Performing Export from a Background Thread
- Copying a Chart to the Clipboard
- Exporting a Video of a Real-Time Updating Chart
- Exporting a 3D Chart
Exporting to Vector Formats (PDF, SVG, XPS)
Exporting to a vector format enables the creation of resolution-independent graphics, ideal for printing or embedding in high-quality documents.
Unlike raster formats such as PNG, JPEG, or BMP, vector exports preserve lines and shapes as true vector elements, allowing charts to remain crisp and sharp at any zoom level.
While SciChart does not currently support direct export to SVG or PDF, it does allow exporting charts to the XPS (XML Paper Specification) vector format:
| Exporting to XPS |
Copy Code |
|---|---|
// Enables higher resolution export with XamlRenderSurface (SDK/Enterprise only) bool useXamlRenderSurface = false; // Target export size, or null for current chart size Size? exportedSize = null; // Save the current chart visual to an XPS file // "What you see is what you get": the visible chart will be exported sciChartSurface.ExportToFile("chart-output.xps", ExportType.Xps, useXamlRenderSurface, exportedSize); | |
Export to PDF
You can print a chart to PDF using the standard PrintDialog along with a virtual printer such as “Microsoft Print to PDF”. This approach exports exactly what is visible on screen as a raster image embedded in a PDF:
| Printing to PDF |
Copy Code |
|---|---|
// Shows the OS Print dialog; pick "Microsoft Print to PDF" sciChartSurface.Print("My Chart Export"); | |
Alternatively, you can export the chart to SciChart’s supported XPS vector format and then convert the XPS file to PDF using a third-party library or tool. There are also a number of online services available that support XPS to PDF conversion.
Exporting Multiple Charts to a Single Image
In some cases, it may be desirable to present multiple related charts together — for example, to share a dashboard snapshot, generate a combined report, or archive visual analytics.
To achieve this with SciChart, we recommend exporting all charts to bitmaps using the SciChart API, and then composing them into a custom layout in code using WPF capabilities.
The example below demonstrates how to export four charts into a 2×2 grid. This is accomplished through the following steps:
- Export each chart to a bitmap using the SciChart export API
- Create a WPF DrawingVisual — a lightweight visual object for drawing vector and bitmap graphics
- Draw the exported bitmaps onto the
DrawingVisualin the desired layout - Render the DrawingVisual to a
RenderTargetBitmap - Save the RenderTargetBitmap to a PNG (or any other supported image format)
The following method demonstrates this process:
| Exporting multiple charts to a grid |
Copy Code |
|---|---|
public static void Export2x2( SciChartSurface scs1, SciChartSurface scs2, SciChartSurface scs3, SciChartSurface scs4, string outputPath, int dpi = 96, int cellGap = 0) // optional spacing between cells { // Export each visible surface to an bitmap var b1 = scs1.ExportToBitmapSource(); var b2 = scs2.ExportToBitmapSource(); var b3 = scs3.ExportToBitmapSource(); var b4 = scs4.ExportToBitmapSource(); // Column widths are the max of each column // row heights are the max of each row int col1Width = Math.Max(b1.PixelWidth, b3.PixelWidth); int col2Width = Math.Max(b2.PixelWidth, b4.PixelWidth); int row1Height = Math.Max(b1.PixelHeight, b2.PixelHeight); int row2Height = Math.Max(b3.PixelHeight, b4.PixelHeight); // Gaps between cells int totalWidth = col1Width + col2Width + (cellGap > 0 ? cellGap : 0); int totalHeight = row1Height + row2Height + (cellGap > 0 ? cellGap : 0); // Composite with DrawingVisual → RenderTargetBitmap var dv = new DrawingVisual(); using (var dc = dv.RenderOpen()) { dc.DrawImage(b1, new Rect(0, 0, col1Width, row1Height)); dc.DrawImage(b2, new Rect(col1Width + cellGap, 0, col2Width, row1Height)); dc.DrawImage(b3, new Rect(0, row1Height + cellGap, col1Width, row2Height)); dc.DrawImage(b4, new Rect(col1Width + cellGap, row1Height + cellGap, col2Width, row2Height)); } var rtb = new RenderTargetBitmap(totalWidth, totalHeight, dpi, dpi, PixelFormats.Pbgra32); rtb.Render(dv); // Encode to PNG var enc = new PngBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(rtb)); using var fs = File.Create(outputPath); enc.Save(fs); } | |
Exporting Multiple Charts to Separate Images
When you need to distribute or archive each chart separately — for example, to enable independent editing, embed visuals into different documents, or automate per-chart reporting — it is often more practical to export each chart as an individual image file, rather than combining them into a single graphic.
Export existing on-screen surfaces (as-is)
| Export on-screen surfaces |
Copy Code |
|---|---|
// Assume you have a list of surfaces already in the UI IList<SciChartSurface> surfaces = new List<SciChartSurface> { surfaceA, surfaceB, surfaceC }; string outputDir = Path.Combine(Environment.CurrentDirectory, "Exports"); Directory.CreateDirectory(outputDir); for (int i = 0; i < surfaces.Count; i++) { var surface = surfaces[i]; string filePath = Path.Combine(outputDir, $"chart_{i + 1:D3}.png"); // export as it is, no size // but can be called with cloning as well surface.ExportToFile(filePath, ExportType.Png, false); } | |
Export N off-screen charts(headless) with numbered names
| Export off-screen charts with numbered names |
Copy Code |
|---|---|
// Pick a target render size for all images var size = new Size(1600, 900); string outputDir = Path.Combine(Environment.CurrentDirectory, "OffscreenExports"); Directory.CreateDirectory(outputDir); // Let’s say we need to export 5 charts int count = 5; for (int i = 0; i < count; i++) { string filePath = Path.Combine(outputDir, $"offscreen_{i + 1:D3}.png"); // Build a surface entirely in code for this iteration (axes + series, etc.) var surface = OffscreenBuildSurfaceForIndex(i, size); // Because it’s off-tree, initialize and layout manually surface.OnLoad(); surface.Measure(size); surface.Arrange(new Rect(0, 0, size.Width, size.Height)); surface.UpdateLayout(); // Export to file (PNG/JPEG/BMP/XPS supported) surface.ExportToFile(filePath, ExportType.Png, useXamlRenderSurface: false, exportedSize: size); } // Method used for creating SciChartSurface in codebehind static SciChartSurface OffscreenBuildSurfaceForIndex(int index, Size size) { var s = new SciChartSurface { Width = size.Width, Height = size.Height }; // Axes s.XAxes.Add(new SciChart.Charting.Visuals.Axes.NumericAxis()); s.YAxes.Add(new SciChart.Charting.Visuals.Axes.NumericAxis()); // Data & series (vary per index as needed) var ds = new SciChart.Charting.Model.DataSeries.XyDataSeries<double, double> { SeriesName = $"Series {index + 1}" }; for (int x = 0; x < 1000; x++) { ds.Append(x, Math.Sin((x + index * 50) * 0.02)); s.RenderableSeries.Add(new SciChart.Charting.Visuals.RenderableSeries.FastLineRenderableSeries { DataSeries = ds }); } return s; } | |
Exporting an Entire View That Contains a Chart
SciChart does not provide built-in functionality for exporting an entire view. However, you can achieve this by capturing the entire container — such as a Window, UserControl, or Grid — that hosts the SciChartSurface along with any other UI elements.
The example below demonstrates this approach using WPF’s RenderTargetBitmap to render and export a UI container to an image:
| Capturing the entire container |
Copy Code |
|---|---|
using System.IO; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; // Assume 'container' is a Grid containing { SciChartSurface, Legend, Buttons, ... } // and is currently visible on screen. var rtb = new RenderTargetBitmap( (int)container.ActualWidth, (int)container.ActualHeight, 96, 96, PixelFormats.Pbgra32); rtb.Render(container); var enc = new PngBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(rtb)); using (var fs = File.Create("container_export.png")) { enc.Save(fs); } | |
Exporting Charts from Multiple Tabs
When your WPF application organizes charts inside a TabControl, you might need to save each chart as an image—even those on tabs that aren’t currently visible. Exporting charts directly from the TabControl lets you capture every tab’s content programmatically, ensuring that all charts are saved with consistent quality without requiring the user to switch tabs manually.
In WPF, exporting charts from hidden tabs is not straightforward:
- Controls in non-selected tabs are often unloaded or never measured/arranged, which makes a simple “as-is” bitmap capture unreliable.
- Attempting to render these visuals directly may result in empty or partially drawn images.
Below is an example of how you can implement a solution to this problem:
| Exporting from multiple Tabs |
Copy Code |
|---|---|
public void ExportAllCharts() { var size = new Size(1600, 900); var outDir = Path.Combine(Environment.CurrentDirectory, "TabExports"); Directory.CreateDirectory(outDir); var surfaces = GetSurfacesByName(Tabs, "Chart"); for (int i = 0; i < surfaces.Count; i++) { var file = Path.Combine(outDir, $"tab_{i + 1:D2}.png"); surfaces[i].ExportToFile(file, ExportType.Png, false, size); } } private static List<SciChartSurface> GetSurfacesByName(TabControl tabs, string surfaceName) { var result = new List<SciChartSurface>(); foreach (var item in tabs.Items) { if (item is TabItem ti && ti.Content is FrameworkElement root) { if (root is SciChartSurface surface) { result.Add(surface); continue; } if (root.FindName(surfaceName) is SciChartSurface scs) result.Add(scs); } } return result; } | |
Showing or Hiding Cursors on an Exported Chart
The key idea is to access the relevant ChartModifier from the cloned SciChartSurface instance and adjust its properties before returning the clone for export.
The following code snippet demonstrates how to retrieve a CursorModifier from the cloned surface and disable it:
| Disabling a CursorModifier |
Copy Code |
|---|---|
protected override SciChartSurfaceBase CreateCloneOfSurfaceInMemory(Size newSize) { // Perform base cloning functionality var cloned = (SciChartSurface)base.CreateCloneOfSurfaceInMemory(newSize); // Getting and disabling single CursorModifier var clonedCursor = ((ModifierGroup)this.ChartModifier).ChildModifiers.FirstOrDefault((x) => x.GetType() == typeof(CursorModifier)); clonedCursor.IsEnabled = false // Or simply clear all Modifiers (notice Legend will be also missed) // ((ModifierGroup)cloned.ChartModifier).ChildModifiers.Clear(); // Return cloned surface return cloned; } | |
Adding Annotations or Visual Elements to an Exported Chart
Adding Annotations, RenderableSeries, or other visual elements directly to the exported chart allows you to modify the output without affecting the original SciChartSurface.
The example below demonstrates how to add a watermark as a TextAnnotation to the exported image:
| Adding a watermark |
Copy Code |
|---|---|
public class SciChartSurfaceEx : SciChartSurface { protected override SciChartSurfaceBase CreateCloneOfSurfaceInMemory(Size newSize) { // Create the default clone var cloned = (SciChartSurface)base.CreateCloneOfSurfaceInMemory(newSize); // Add a watermark only to the clone // May be useful for docs // Also you may add any other annotation like this to a resulted surface cloned.Annotations.Add(new TextAnnotation { Text = "Watermark text here!", CoordinateMode = AnnotationCoordinateMode.Relative, X1 = 0.9, Y1 = 0.9, HorizontalAnchorPoint = HorizontalAnchorPoint.Right, VerticalAnchorPoint = VerticalAnchorPoint.Bottom, Opacity = 0.5 }); // Return the modified clone; the original surface remains unchanged return cloned; } } | |
Placing Custom UI Elements on an Exported Chart
It is possible to add and position any WPF UI elements on a cloned SciChartSurface using the CustomAnnotation, which allows embedding custom content and positioning it through the Annotations API.
The example below shows how to use CustomAnnotation to overlay a TextBlock on the exported chart without affecting the original surface:
| Overlaying a TextBlock |
Copy Code |
|---|---|
using SciChart.Charting.Visuals.Annotations; // Any WPF control you want to export along with the chart var myControl = new System.Windows.Controls.TextBlock { Text = "Extra info", FontSize = 16 }; // Place it at a desired chart coordinate (e.g., relative 0..1) var custom = new CustomAnnotation { Content = myControl, X1 = 0.02, Y1 = 0.98, CoordinateMode = AnnotationCoordinateMode.Relative }; sciChartSurface.Annotations.Add(custom); // Perform export sciChartSurface.ExportToFile("chart_with_control.png", ExportType.Png, useXamlRenderSurface: false, exportedSize: null); | |
Changing the Theme or Background Color for Export
If your original chart uses a dark theme, but you need to export images (e.g., for documents or reports) with a light theme, without changing the theme on the original SciChartSurface, you can achieve this using the following approach:
| Exporting with a light theme |
Copy Code |
|---|---|
public class SciChartSurfaceEx : SciChartSurface { protected override SciChartSurfaceBase CreateCloneOfSurfaceInMemory(Size newSize) { // Create the default clone var cloned = (SciChartSurface)base.CreateCloneOfSurfaceInMemory(newSize); // Change theme on the CLONED surface ThemeManager.SetTheme(cloned, "Chrome"); // Return the modified clone; the original surface remains unchanged return cloned; } } | |
Performing Export from a Background Thread
Since export relies on WPF visuals, it must be executed on an STA (Single Threaded Apartment) UI thread. If you're initiating the export from a background thread, you’ll need to marshal the call to the UI thread using the Dispatcher.
The example below demonstrates how to do this:
| Exporting from a background thread using the Dispatcher |
Copy Code |
|---|---|
await Application.Current.Dispatcher.InvokeAsync(() => { sciChartSurface.ExportToFile("chart.png", ExportType.Png, false, null); }); | |
For headless/off-screen export (no UI), run your exporter on a dedicated STA thread that you create:
| Off-screen export from a dedicated STA thread |
Copy Code |
|---|---|
var t = new Thread(() => { // Build surface, Measure/Arrange, Export... }) { IsBackground = true }; t.SetApartmentState(ApartmentState.STA); t.Start(); t.Join(); | |
Copying a Chart to the Clipboard
You can easily export a chart to a Bitmap and copy it to the Clipboard:
| Export to Clipboard |
Copy Code |
|---|---|
var bmp = sciChartSurface.ExportToBitmapSource(false, null); System.Windows.Clipboard.SetImage(bmp); | |
Exporting a Video of a Real-Time Updating Chart
SciChart does not support direct video export. However, a common approach is to:
- Render a sequence of images, one per frame, by capturing the chart as it updates
- Encode the image sequence into a video using a tool like FFmpeg or another video encoder
This method captures exactly what is displayed on screen for each frame, allowing you to export dynamic charts or animations as video content.
| Exporting a sequence of images |
Copy Code |
|---|---|
public async Task ExportFramesOnScreenAsync( SciChartSurface sciChartSurface, IXyDataSeries<double, double> dataSeries, string framesDir, int frameCount = 300, int fps = 30) { Directory.CreateDirectory(framesDir); // Animate a sine wave by phase for (int i = 0; i < frameCount; i++) { double phase = i * 0.1; using (sciChartSurface.SuspendUpdates()) { dataSeries.Clear(); for (int x = 0; x <= 1000; x++) { double y = Math.Sin(2.0 * Math.PI * (x / 100.0) + phase); dataSeries.Append(x, y); } } string path = Path.Combine(framesDir, $"frame_{i:0000}.png"); // Export current on-screen state as PNG sciChartSurface.ExportToFile(path, ExportType.Png, false); await Task.Delay(1000 / fps); } } | |
You can also use off-screen export to simulate changes in the chart or its content. The main idea is to generate a sequence of images, each representing a frame, which can later be encoded into a video.
There are many third-party libraries available to help with encoding images into a video file. Alternatively, you can use a terminal-based tool like FFmpeg.
To do this, open a terminal in the folder containing your exported frames (e.g., frame_0000.png, frame_0001.png, etc.) and run one of the following commands:
Generating an MP4 file (H.264 encoding, widely compatible)
ffmpeg -framerate 30 -i frame_%04d.png -c:v libx264 -pix_fmt yuv420p -crf 18 -preset slow output.mp4
Exporting a 3D Chart
Exporting a 3D chart in WPF requires a slightly different approach than 2D rendering. Because SciChart 3D relies on real-time GPU rendering, it can only capture a raster image of the chart exactly as it appears on screen. In other words, the chart must be visible and fully rendered in the viewport when the export command runs, and the output will reflect the current camera angle, zoom level, and any active visual effects.
| Exporting a 3D Chart |
Copy Code |
|---|---|
// Assumes sciChartSurface3D is visible on screen string fileName = Path.Combine(Environment.CurrentDirectory, "chart3d.png"); sciChartSurface3D.ExportToFile(fileName, ExportType.Png); | |